from datetime import datetime

import pandas as pd

from db.dao import StockLifelineDao
from db.models import StockLifeline
from service.stock.common import BaseToolUtil, ProfitUtil, VolumeHandle
from utils.CommonEnum import LifelineTypeEnum, LineModeEnum, LinePositionEnum
from utils.util import CommonUtil


class Lifeline:
    def __init__(self, pd_data, stock_code, stock_name):
        self.stock_code = stock_code
        self.stock_name = stock_name
        self.pd_data = pd_data
        self.drift = 2

    def create_line(self):
        pd_temp = self.pd_data.copy()

        pd_temp = pd_temp.tail(500)

        VolumeHandle(pd_temp).rising_band()
        pd_temp.loc[pd_temp['chg_vol_signal'] == 1, 'lifeline'] = pd_temp['close']
        pd_lifeline = LifelineHander.create_lifeline(pd_temp)
        self.store_lifeline(pd_lifeline)

    def store_lifeline(self, pd_lifeline):
        lifeList = []
        to_dict = pd_lifeline.to_dict()
        lifeline_dict = to_dict.get('lifeline')
        for key, value in lifeline_dict.items():
            lifeline = StockLifeline()
            setattr(lifeline, 'stock_code', self.stock_code)
            setattr(lifeline, 'stock_name', self.stock_name)
            setattr(lifeline, 'line_code', CommonUtil.get_uuid())
            setattr(lifeline, 'line_type', LifelineTypeEnum.HORIZON.code)
            setattr(lifeline, 'line_mode', LineModeEnum.INCREASE.code)
            setattr(lifeline, 'point_1_time', key)
            setattr(lifeline, 'point_1_price', value)
            setattr(lifeline, 'create_time', datetime.now())
            lifeList.append(lifeline)

        StockLifelineDao().saveList(lifeList)


class LifelineHander:

    @staticmethod
    def create_lifeline(pd_temp, drift=0.05):
        '''
        ����������
        :param drift: ������֮��ļ��Ҫ>=drift
        :return:
        '''
        pd_lifeline = pd.DataFrame(
            pd_temp.loc[(pd_temp['lifeline'].notnull()), 'lifeline'])
        pd_lifeline.drop_duplicates(keep='first', inplace=True)
        pd_lifeline.sort_values(by='lifeline', inplace=True)

        while True:
            pd_lifeline.loc[:, 'pct_chg'] = pd_lifeline.pct_change()
            condition = (pd_lifeline['pct_chg'] < drift) & (
                    pd_lifeline['pct_chg'].shift(1) > drift)
            aa_any = condition.any()
            if not aa_any:
                break

            pd_lifeline.drop(pd_lifeline[condition].index, inplace=True)
            pd_lifeline.drop('pct_chg', axis=1, inplace=True)

        return pd_lifeline

    def in_line_scope(self, cur_price, line_price):
        '''
             �жϼ�λ�Ƿ��������߷�Χ�ڷ�Χ
        '''
        if not line_price:
            return False
        chg = BaseToolUtil.ABS(ProfitUtil.calculationChg(cur_price, line_price))
        return chg <= self.drift * 5

    def price_line_position(self, day_date, price_lines, drift=0.03):
        '''
        todo ������open,close,high,low ������   5.18
        '''
        if len(price_lines) == 0:
            return None
        result_msg = []
        for line_price in price_lines:

            # ����������
            line_upper = line_price * (1 + drift)
            # ����������
            line_lower = line_price * (1 - drift)

            _open = day_date['open']
            _cur = day_date['close']
            _pctChg = day_date['pctChg']
            # _high = day_date['high']
            # _low = day_date['low']
            if _pctChg > 0:
                if _cur > line_upper:
                    result_msg.append(LinePositionEnum.RISE.msg)
                elif (_cur >= line_lower) & (_cur <= line_upper):
                    result_msg.append(LinePositionEnum.PRESSURE.msg)
            else:
                if _cur < line_lower:
                    result_msg.append(LinePositionEnum.FALL.msg)
                elif (_cur >= line_lower) & (_cur <= line_upper):
                    result_msg.append(LinePositionEnum.SUPPORT.msg)

        if len(result_msg) > 0:
            return ','.join(set(result_msg))
        return ''

    def filter_lines_by_price(self, pd_sort, cur_price):
        '''
             ���˵�ǰ��λ������������
        '''
        pd_line_temp = pd_sort.sort_values(by='lifeline')
        closest_index = (pd_line_temp['lifeline'] - cur_price).abs().argsort()[0]
        closest_val = pd_line_temp.iloc[closest_index]['lifeline']
        if cur_price > closest_val:
            left_idx = closest_index
            left_val = closest_val
            right_idx = closest_index + 1
            if right_idx >= pd_line_temp.shape[0]:
                return left_idx, left_val, None, None
            right_val = pd_line_temp.iloc[right_idx]['lifeline']
            return left_idx, left_val, right_idx, right_val
        elif cur_price <= closest_val:
            right_idx = closest_index
            right_val = closest_val
            left_idx = closest_index - 1
            if left_idx < 0:
                return None, None, right_idx, right_val
            left_val = pd_line_temp.iloc[left_idx]['lifeline']
            return left_idx, left_val, right_idx, right_val

    def breakthrough_line(self):
        '''
            ͻ��������
        '''

        pass
